# -*- coding: utf-8 -*-
# created on 2017/01/17

from __future__ import division
from sympy import sympify, Abs
from collections import namedtuple
from mathsolver.functions.base import BaseFunction, BaseIneq, BaseIneqs
from mathsolver.functions.hanshu.helper import check_inter, check_jiou
from mathsolver.functions.hanshu.helper import reverse_op
from mathsolver.functions.hanshu.jiou_dingyi import dairu_jiou2
from mathsolver.functions.hanshu.zhouqi import has_f_or_minusf, has_f, has_minusf
from mathsolver.functions.sympy_utils import get_all_child

# 方程 eq1 或者 eq2
eq_or = namedtuple('eq_or', ['eqs'])


def jioudandiao_infer_budengshi(jiou, inter, dandiao, ineq):
    """
    函数奇偶性和单调性解不等式
    """

    left, operator, right = ineq
    gx, hx = left.args[0], right.args[0]
    jiou = check_jiou(jiou)

    # 奇函数需要讨论区间是否包含 0
    if '奇' in jiou:
        # 如果区间包含 0
        if 0 in inter:
            if '增' in dandiao:
                res = [BaseIneq([gx, operator, hx])]
            else:
                res = [BaseIneq([gx, reverse_op(operator), hx])]
        # 如果不包含 0
        else:
            if '增' in dandiao:
                if operator in ['<', '<=']:
                    ineq = BaseIneq([gx, operator, -Abs(hx)])
                    ineq.is_or = True
                    ineqs = BaseIneqs([[0, '<', gx], [gx, operator, Abs(hx)]])
                    ineqs.is_or = True
                    res = [ineq, ineqs]
                else:
                    ineq = BaseIneq([gx, operator, Abs(hx)])
                    ineq.is_or = True
                    ineqs = BaseIneqs([[0, '>', gx], [gx, operator, -Abs(hx)]])
                    ineqs.is_or = True
                    res = [ineq, ineqs]
            else:
                if operator in ['<', '<=']:
                    ineq = BaseIneq([gx, operator, Abs(hx)])
                    ineq.is_or = True
                    ineqs = BaseIneqs([[0, '>', gx], [gx, operator, -Abs(hx)]])
                    ineqs.is_or = True
                    res = [ineq, ineqs]
                else:
                    ineq = BaseIneq([gx, operator, -Abs(hx)])
                    ineq.is_or = True
                    ineqs = BaseIneqs([[0, '<', gx], [gx, operator, Abs(hx)]])
                    ineqs.is_or = True
                    res = [ineq, ineqs]

    # 偶函数对区间没有要求
    else:
        inter_min, inter_max = inter._inf, inter._sup
        if (inter_min >= 0 and '增' in dandiao) or (inter_max >= 0 and '减' in dandiao):
            res = [BaseIneq([Abs(gx), operator, Abs(hx)])]
        else:
            res = [BaseIneq([Abs(gx), reverse_op(operator), Abs(hx)])]

    step = "根据%s函数的对称性可知：%s" % (jiou, '，或者 '.join(item.printing() for item in res))
    return res, step


def check_type2(ineq, jiou):
    """检查是否是类型二: f(m) + f(m-2) > 0"""
    left, op, right = ineq
    if '奇' in jiou:
        if left == 0:
            left, right = right, left
            op = reverse_op(op)
        if right == 0:
            item1, item2 = left.args
            if has_f(item1) and has_f(item2):
                res, (step1, step2) = dairu_jiou2(item2, jiou)
                left, right = item1, -res
                ineq = [left, op, right]
                step3 = '所以原不等式等价于 %s %s %s' % (str(left), op, str(right))
                return ineq, (step1, step2, step3)


def normalize_ineq(ineq, jiou):
    """把 ineq 转化成 "f(*) < f(*)" 的格式
    可能运用到奇偶性质转化"""
    left, op, right = ineq

    # 类型一：不需要转化
    if has_f(left) and has_f(right):
        return ineq

    # 标准化不等式，即类型二
    expr = left - right

    minusfs = get_all_child(expr, has_minusf)  # -f(*)
    fs = get_all_child(expr, has_f)  # f(*)

    # 如果含有 -f(*)
    if minusfs:
        minusf = minusfs[0]
        left = expr - minusf
        right = -minusf
        if has_f(left):
            return [left, op, right]
        elif has_minusf(left):
            res, _ = dairu_jiou2(left, jiou)
            return [res, op, right]
        else:
            raise ValueError('无法将不等式 %s 转换成 f(*) < f(*) 的格式' % ineq)

    # 如果不含有 -f(*)
    else:
        f = fs[0]
        left = expr - f
        right = -f
        res, _ = dairu_jiou2(right, jiou)
        return [left, op, res]


class JiOuDanDiaoBuDengShi001(BaseFunction):
    """函数奇偶性与单调性解不等式：输入不含有函数值 f(a)=b"""

    def solver(self, *args):
        # 处理输入
        jiou, inter, dandiao, ineq = args
        inter, ineq = check_inter(inter), ineq.value
        ineq_og = [sympify(ineq[0]), ineq[1], sympify(ineq[2])]

        ineq = normalize_ineq(ineq_og, jiou)
        if ineq != ineq_og:
            self.steps.append(["", "根据函数奇偶性，把不等式转化为 %s %s %s" % (str(ineq[0]), ineq[1], str(ineq[2]))])

        # 函数奇偶性和单调性解不等式
        res, step = jioudandiao_infer_budengshi(jiou, inter, dandiao, ineq)
        self.steps.append(["", step])
        self.output.extend(res)
        self.label.add("函数奇偶性与单调性解不等式")
        return self


def hanshuzhi_zhuanhua_budengshi(func, ineq):
    """函数值转化不等式： f[g(x)] < b, f[h(x)] = b =>  f[g(x)] < f[h(x)]"""
    func_expr, func_val = sympify('%s(%s)' % (func.name, func.var)), func.expression
    left, op, right = ineq
    if left.is_Atom:
        left = left.subs(func_val, func_expr)
    elif right.is_Atom:
        right = right.subs(func_val, func_expr)

    ineq = [left, op, right]
    step = '把 %s 代入不等式得：%s %s %s' % (func.printing(), left, op, right)
    return ineq, step


def check_type4(ineq, jiou):
    """检查是否是类型四"""
    left, op, right = ineq

    if left.is_Atom and not has_f(right):
        left, right = right, left
        op = reverse_op(op)

    if right.is_Atom and not has_f(left):
        item1, item2 = left.as_independent(sympify('-x'))
        if has_f_or_minusf(item1) and has_f_or_minusf(item2):
            res, (step1, step2) = dairu_jiou2(item2, jiou)
            left = left.subs(item2, res)
            assert left.is_Mul
            const, fx = left.args
            left, right = fx, right / const
            ineq = [left, op, right]
            step3 = '所以原不等式等价于 %s %s %s' % (str(left), op, str(right))
            return ineq, (step1, step2, step3)


def contain_f(expr):
    """表达式是否含有 f(x)"""
    if get_all_child(expr, has_f):
        return True


def check_type5(ineq):
    """检查是否是类型五"""
    left, op, right = ineq
    if left == 0:
        left, right = right, left
        op = reverse_op(op)

    op2 = reverse_op(op)
    if right == 0:
        if left.is_Mul:
            item1, item2 = left.args
            if op in {'>', '>='}:
                # 确保 item1 不含 f(), item2 含有 f()
                if contain_f(item1):
                    item1, item2 = item2, item1
                ineqs1 = [[item1, op, 0], [item2, op, 0]]
                ineqs2 = [[item1, op2, 0], [item2, op2, 0]]
                step = '由题意知； {i1} {op} 0, {i2} {op} 0 或者 {i1} {op2} 0, {i2} {op2} 0'.format(
                    i1=item1, i2=item2, op=op, op2=op2)
            else:
                if contain_f(item1):
                    item1, item2 = item2, item1
                ineqs1 = [[item1, op, 0], [item2, op2, 0]]
                ineqs2 = [[item1, op2, 0], [item2, op, 0]]
                step = '由题意知； {i1} {op} 0, {i2} {op2} 0 或者 {i1} {op2} 0, {i2} {op} 0'.format(
                    i1=item1, i2=item2, op=op, op2=op2)

            return (ineqs1, ineqs2), step


class JiOuDanDiaoBuDengShi002(BaseFunction):
    """函数奇偶性与单调性解不等式：输入含有函数值 f(a)=b"""

    def solver(self, *args):
        # 处理输入
        jiou, inter, dandiao, func, ineq = args
        inter, ineq = check_inter(inter), ineq.value
        ineq = [sympify(ineq[0]), ineq[1], sympify(ineq[2])]

        # 检查第四类
        type4 = check_type4(ineq, jiou)
        if type4:
            ineq, (step1, step2, step3) = type4
            self.steps.extend([['', step1], ['', step2], ['', step3]])

        # 检查第五类
        type5 = check_type5(ineq)
        if type5:
            (ineqs1, ineqs2), step = type5
            self.steps.append(['', step])
            flag = '一'
            for ineqs in (ineqs1, ineqs2):
                self.steps.append(['', '考虑第%s种情况：' % flag])
                flag = '二'
                ineq_wo_f, ineq_w_f = ineqs
                step_solver = JiOuDanDiaoBuDengShi002().solver(jiou, inter, dandiao, func, BaseIneq(ineq_w_f))
                self.steps.extend(step_solver.steps)
                step_ineq = step_solver.output[0]
                self.output.append(BaseIneqs([ineq_wo_f, step_ineq.value]))

            self.label.add("函数奇偶性与单调性解不等式")
            return self

        # 函数值转化不等式
        ineq, step0 = hanshuzhi_zhuanhua_budengshi(func, ineq)

        # 函数奇偶性和单调性解不等式
        relation, step = jioudandiao_infer_budengshi(jiou, inter, dandiao, ineq)
        self.steps.extend([["", step0], ["", step]])
        self.output.append(BaseIneq(relation))
        self.label.add("函数奇偶性与单调性解不等式")
        return self


if __name__ == '__main__':
    pass
